#region Copyright (C) 2005-2006 Team MediaPortal

/* 
 *	Copyright (C) 2005-2006 Team MediaPortal
 *	http://www.team-mediaportal.com
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Xml;
using System.Drawing;
using MediaPortal.GUI.Library;

namespace DotNetGear.BestRussianTV
{
    /// <summary>
    /// This class gives you access to video archive.
    /// </summary>
    public class VideoArchive
    {

        private class Debug
        {
            public static void WriteLine(string a)
            {
                Log.Error("Video Archive Debug {0}", a);
            }
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="provider">www.bestrussiantv.com</param>
        /// <param name="url">http://www.connectv.ca/wsapi/pvr/</param>
        /// <param name="login"></param>
        /// <param name="password"></param>
        public VideoArchive(string provider, string url, string login, string password)
        {
            _url = url; if (_url[_url.Length - 1] != '/') _url += "/";
            _provider = provider;
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://" + _provider + "/login.asp");
            CookieContainer cc = new CookieContainer();
            req.CookieContainer = cc;
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            byte[] b = new ASCIIEncoding().GetBytes("login=" + login + "&password=" + password);
            req.ContentLength = b.Length;
            Stream ns = req.GetRequestStream();
            ns.Write(b, 0, b.Length);
            ns.Close();

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();
            res.Cookies = req.CookieContainer.GetCookies(req.RequestUri);
            StreamReader r = new StreamReader(res.GetResponseStream());
            string line;
            while ((line = r.ReadLine()) != null)
            {
                if (line.Contains("window.open(\"/tv_popup.asp?ch"))
                {
                    string l = "login=";
                    string p = "password=";
                    string pi = "pid=";
                    int ls = line.IndexOf(l) + l.Length;
                    int le = line.IndexOf(p) - 1;
                    int ps = line.IndexOf(p) + p.Length;
                    int pe = line.IndexOf("&", ps);
                    int pis = line.IndexOf(pi) + pi.Length;
                    //int pie = ?
                    _uid = line.Substring(ls, le - ls);
                    _pwd = line.Substring(ps, pe - ps);
                    _pid = line.Substring(pis, 1);
                    break;
                }
            }
            res.Close();
            Debug.WriteLine("Login respond:" + line);
            Debug.WriteLine("Login info " + _uid + " " + _pwd);
            if((_uid == string.Empty)|(_pwd == string.Empty))
            {
                throw new Exception("Could not login to " + provider + ".");
            }            
        }

        private readonly string _provider = string.Empty;
        private readonly string _url = string.Empty;
        private readonly string _uid = string.Empty; /*aka phoneno, login*/
        private readonly string _pwd = string.Empty;
        private readonly string _pid = "2";
        private readonly string _aid = "2";

        /// <summary>
        /// Class represents requested programm.
        /// </summary>
        public class Program
        {
            public readonly ProgramItem[] Items;
            public readonly Date Date;
            public readonly Channel Channel;           
            
            public Program(Date date, Channel channel, ArrayList items)
            {
                Items = (ProgramItem[])items.ToArray(typeof(ProgramItem));
                Channel = channel;
                Date = date;
            }

            public static bool operator !=(Program x, Program y)
            {
                if (object.Equals(x, y))
                {
                    return false;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return !y.Equals(x);
                }
                return true;
            }

            public static bool operator ==(Program x, Program y)
            {
                if (object.Equals(x, y))
                {
                    return true;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return y.Equals(x);
                }
                return false;
            }

            public override bool Equals(object o)
            {
                if (object.Equals(o, null))
                {
                    return false;
                }
                if (base.Equals(o))
                {
                    return true;
                }
                Program r = o as Program;
                if (!object.Equals(r, null))
                {
                    //TODO: Compare Items ?
                    return ((this.Date == r.Date) & (this.Channel == r.Channel));
                }
                else
                {
                    return false;
                }
            }

            //TODO: Implement?
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
 
        }

        /// <summary>
        /// Class represents item of program.
        /// </summary>
        public class ProgramItem
        {
            public readonly string Info;
            public readonly string Time;
            public readonly string Id;
            public readonly Channel Channel;
            public readonly Date Date;

            public ProgramItem(Channel channel, Date date, string info, string time, string id)
            {
                Info = info;
                Time = time;
                Id = id;
                Channel = channel;
                Date = date;
            }

            public override string ToString()
            {
                return Time + "  " + Info;
            }

            public static bool operator !=(ProgramItem x, ProgramItem y)
            {
                if (object.Equals(x, y))
                {
                    return false;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return !y.Equals(x);
                }
                return true;
            }

            public static bool operator ==(ProgramItem x, ProgramItem y)
            {
                if (object.Equals(x, y))
                {
                    return true;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return y.Equals(x);
                }
                return false;
            }

            public override bool Equals(object o)
            {
                if (object.Equals(o, null))
                {
                    return false;
                }
                if (base.Equals(o))
                {
                    return true;
                }
                ProgramItem r = o as ProgramItem;
                if (!object.Equals(r, null))
                {
                    return ((this.Id == r.Id) & (this.Info == r.Info) & (this.Time == r.Time));
                }
                else
                {
                    return false;
                }
            }

            //TODO: Implement?
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
        }

        /// <summary>
        /// Class represents channel info.
        /// </summary>
        public class Channel
        {
            public readonly string Name;
            public readonly string Id;

            public Channel(string name, string id)
            {
                Name = name;
                Id = id;
            }
            
            public override string ToString()
            {
                return Name + " " + Id;
            }

            public static bool operator !=(Channel x, Channel y)
            {
                if (object.Equals(x, y))
                {
                    return false;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return !y.Equals(x);
                }
                return true;
            }

            public static bool operator ==(Channel x, Channel y)
            {
                if (object.Equals(x, y))
                {
                    return true;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return y.Equals(x);
                }
                return false;
            }

            public override bool Equals(object o)
            {
                if (object.Equals(o, null))
                {
                    return false;
                }
                if (base.Equals(o))
                {
                    return true;
                }
                Channel r = o as Channel;      
                if (!object.Equals(r, null))
                {
                    return ((this.Id == r.Id) & (this.Name == r.Name));
                }
                else
                {
                    return false;
                }
            }

            //TODO: Implement?
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
        }

        /// <summary>
        /// Class represents available date (time) of archive.
        /// </summary>
        public class Date
        {
            public  string Value;
            public  string Id;

            public Date(string value, string id)
            {
                Value = value; 
                Id = id;                             
            }

            public override string ToString()
            {
                return Value;
            }

            public static bool operator !=(Date x, Date y)
            {
                if (object.Equals(x, y))
                {
                    return false;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return !y.Equals(x);
                }
                return true;
            }

            public static bool operator ==(Date x, Date y)
            {
                if (object.Equals(x, y))
                {
                    return true;
                }
                if (object.Equals(x, null) && object.Equals(y, null))
                {
                    return y.Equals(x);
                }
                return false;
            }

            public override bool Equals(object o)
            {
                if (object.Equals(o, null))
                {
                    return false;
                }
                if (base.Equals(o))
                {
                    return true;
                }
                Date r = o as Date;
                if (!object.Equals(r, null))
                {
                    return ((this.Id == r.Id) & (this.Value == r.Value));
                }
                else
                {
                    return false;
                }
            }

            //TODO: Implement?
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
 
        }

        /// <summary>
        /// Contains two arrays of requested channels and available dates.
        /// </summary>
        public class ChannelsAndDates
        {
            public ChannelsAndDates(ArrayList channels, ArrayList dates)
            {
                Dates = (Date[])dates.ToArray(typeof(Date));
                Channels = (Channel[])channels.ToArray(typeof(Channel));
            }
            public readonly Date[] Dates;
            public readonly Channel[] Channels;
        }

        /// <summary>
        /// Requests channel program from server.
        /// </summary>
        /// <param name="date"></param>
        /// <param name="channel"></param>
        /// <returns></returns>
        public Program GetProgram(Channel channel, Date date)
        {
            ArrayList program = new ArrayList();

            WebClient myWebClient = new WebClient();
            myWebClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
            NameValueCollection myQueryStringCollection = new NameValueCollection();
            myQueryStringCollection.Add("time", date.Id);
            myQueryStringCollection.Add("channel", channel.Id);
            myQueryStringCollection.Add("uid", _uid);// ""
            myQueryStringCollection.Add("pwd", _pwd);// ""
            myQueryStringCollection.Add("pid", _pid);// ""
            myQueryStringCollection.Add("aid", _aid);
            myWebClient.QueryString = myQueryStringCollection;
            myWebClient.Encoding = Encoding.UTF8;
            string s = myWebClient.DownloadString(_url + "get_pvr_epg.asp");

            XmlDocument xd = new XmlDocument();
            xd.LoadXml(s);
            
            foreach (XmlNode n in xd.DocumentElement.SelectNodes("/table/tr/td/table/tbody/tr"))
            {
                XmlNode td0 = n.SelectNodes("./td")[0]; //Time
                XmlNode td1 = n.SelectNodes("./td")[2]; //Info and href

                if ((td0 != null) & (td1 != null))
                {
                    string id = string.Empty;
                    if (td1["a"] != null)
                    {
                        if (td1["a"].Attributes != null)
                            if (td1["a"].Attributes["href"] != null) //Program href available
                            {
                                id = td1["a"].Attributes["href"].Value;
                                id = id.Replace("javascript:OpenMediaPlayer(", string.Empty);
                                id = id.Replace(")", string.Empty);
                            }
                    }
                    ProgramItem pi = new ProgramItem(channel, date, td1.InnerText, td0.InnerText, id);
                    program.Add(pi);
                    Debug.WriteLine(pi + " " + id);
                }
            }
            return new Program(date, channel, program);
        }


        /// <summary>
        /// Requests available channels and dates (time).
        /// </summary>
        /// <returns></returns>
        public ChannelsAndDates GetChannelsAndDates()
        { 
            ArrayList channels = new ArrayList();
            ArrayList dates = new ArrayList();

            WebClient myWebClient = new WebClient();
            myWebClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
            NameValueCollection myQueryStringCollection = new NameValueCollection();
            myQueryStringCollection.Add("phoneno", _uid);
            myQueryStringCollection.Add("pwd", _pwd);
            myQueryStringCollection.Add("pid", _pid);
            myQueryStringCollection.Add("aid", _aid);
            myWebClient.QueryString = myQueryStringCollection;
            myWebClient.Encoding = Encoding.UTF8;
            string s = myWebClient.DownloadString(_url + "pvr_pageAPI.asp");
            //Bug fix, input tag is not closed.
            s = s.Replace("<input id=\"btnRefresh\" type=\"image\" src=\"button_display.gif\" alt=\"\" onClick=\"return btnRefresh_onclick();\">",
                "<input id=\"btnRefresh\" type=\"image\" src=\"button_display.gif\" alt=\"\" onClick=\"return btnRefresh_onclick();\"></input>");

            int si = s.IndexOf("<BODY");
            int ei = s.IndexOf("/BODY>", si);
            s = s.Substring(si, ei - si + 6);
           
            XmlDocument xd = new XmlDocument();
            xd.LoadXml(s);

            foreach (XmlNode n in xd.DocumentElement.SelectNodes("/BODY/table/tr/td/select"))
            {

                if (n.Attributes["id"] == null)
                {
                    Debug.WriteLine("Attribute 'id' is not found. Node text:" + n.InnerText);
                }
                else
                {

                    Debug.WriteLine(n.Attributes["id"].Value);

                    if (n.Attributes["id"].Value == "ch")
                    {
                        foreach (XmlNode x in n.ChildNodes)
                        {
                            channels.Add(new Channel(x.InnerText, x.Attributes["value"].Value));
                            Debug.WriteLine(x.Attributes["value"].Value + " " + x.InnerText);
                        }
                    }

                    if (n.Attributes["id"].Value == "dt")
                    {
                        foreach (XmlNode x in n.ParentNode.ChildNodes)
                        {
                            if (x.InnerText != string.Empty) //Bug with dates select tag.
                            {
                                if (x.Attributes["value"] != null)
                                {
                                    dates.Add(new Date(x.InnerText, x.Attributes["value"].Value));
                                    Debug.WriteLine(x.Attributes["value"].Value + " " + x.InnerText);
                                }
                                else
                                {
                                    Debug.WriteLine("Attribute 'value' is not found. " + x.InnerText);
                                }
                            }
                        }
                    }

                }
            }

            return new ChannelsAndDates(channels, dates);
        }

        /// <summary>
        /// Returns Url (MMS) for requested ProgramItem.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public string GetPlayersUrl(ProgramItem item)
        {
            WebClient myWebClient = new WebClient();
            myWebClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
            NameValueCollection myQueryStringCollection = new NameValueCollection();
            myQueryStringCollection.Add("id", item.Id);
            myQueryStringCollection.Add("phoneno", _uid);
            myQueryStringCollection.Add("pwd", _pwd);
            myQueryStringCollection.Add("POSTBACKURL", "player.asp");
            myQueryStringCollection.Add("pid", _pid);
            myQueryStringCollection.Add("aid", _aid);
            myWebClient.QueryString = myQueryStringCollection;
            myWebClient.Encoding = Encoding.UTF8;
            string s = myWebClient.DownloadString(_url + "pvr_streamAPI.asp");

            int si = s.IndexOf("<EMBED src=");
            int ei = s.IndexOf('"', si + 12);
            s = s.Substring(si + 12, ei - (si + 12));

            Debug.WriteLine("Url params: " + item.Id + " " + _uid + " " + _pwd + " " + _pid  + " " + _aid);
            Debug.WriteLine(s);
            return s;
        }

        public string GetChannelIconUrl(Channel channel)
        {
            return ("http://" + _provider + "/images/ch" + channel.Id + ".gif");
        }
    }
}
